using System.Collections.Generic;
using UnityEngine;

public class PVSRuntimeCuller : MonoBehaviour
{
    public PVSData pvs;
    public List<Renderer> targets = new();
    public Transform watcher;
    public Vector3 watcherExtents = Vector3.zero;
    public float tick = 0.1f;

    float _next;

    void Reset(){ if(!watcher) watcher = Camera.main ? Camera.main.transform : transform; }

    void Update()
    {
        if (!pvs || watcher==null || targets.Count!=pvs.objectCount) return;
        if (Time.time < _next) return;
        _next = Time.time + Mathf.Max(0.01f, tick);

        var cells = OverlapCells(watcher.position, watcherExtents);
        var vis = new bool[pvs.objectCount];

        foreach (int ci in cells)
        {
            var bits = pvs.cellBits[ci];
            if (bits==null) continue;
            for (int i=0;i<vis.Length;i++) vis[i] |= bits[i];
        }
        for (int i=0;i<vis.Length;i++)
            if (targets[i]) targets[i].enabled = vis[i];
    }

    List<int> OverlapCells(Vector3 pos, Vector3 ext)
    {
        List<int> list = new(4);
        ToCell(pos-ext, out int i0,out int j0,out int k0);
        ToCell(pos+ext, out int i1,out int j1,out int k1);
        i0=Mathf.Clamp(i0,0,pvs.grid.x-1); i1=Mathf.Clamp(i1,0,pvs.grid.x-1);
        j0=Mathf.Clamp(j0,0,pvs.grid.y-1); j1=Mathf.Clamp(j1,0,pvs.grid.y-1);
        k0=Mathf.Clamp(k0,0,pvs.grid.z-1); k1=Mathf.Clamp(k1,0,pvs.grid.z-1);
        for(int i=i0;i<=i1;i++)
        for(int j=j0;j<=j1;j++)
        for(int k=k0;k<=k1;k++)
            list.Add((i*pvs.grid.y + j)*pvs.grid.z + k);
        return list;
    }

    void ToCell(Vector3 p, out int ix,out int iy,out int iz)
    {
        float tx = Mathf.InverseLerp(pvs.min.x, pvs.max.x, p.x);
        float ty = Mathf.InverseLerp(pvs.min.y, pvs.max.y, p.y);
        float tz = Mathf.InverseLerp(pvs.min.z, pvs.max.z, p.z);
        ix = Mathf.FloorToInt(tx * pvs.grid.x);
        iy = Mathf.FloorToInt(ty * pvs.grid.y);
        iz = Mathf.FloorToInt(tz * pvs.grid.z);
    }
}
